package com.yjck.ijpay.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;

import com.alipay.api.domain.MessageTemplate;
import com.yjck.ijpay.config.CommonConstant;
import com.yjck.ijpay.dto.WxPayDTO;
import com.yjck.ijpay.lock.RedissonDistributedLock;
import com.yjck.ijpay.lock.ZLock;
import com.yjck.ijpay.pojo.BaseResponse;
import com.yjck.ijpay.pojo.XhMember;
import com.yjck.ijpay.pojo.XhMemberPay;
import com.yjck.ijpay.service.IPayService;
import com.yjck.ijpay.config.pay.WxPayCallback;
import com.yjck.ijpay.config.pay.WxRefundCallback;
import com.yjck.ijpay.utils.WeChatUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author lyz
 * @version [1.0, 2021-04-25]
 * @Description: 支付逻辑
 */
@Slf4j
@Service
public class IPayServiceImpl implements IPayService {

    //    @Autowired
//    private IXhMemberService xhMemberService;
//    @Autowired
//    private IXhMemberDepositOrderService xhMemberDepositOrderService;
//    @Autowired
//    private IXhMemberComboOrderService xhMemberComboOrderService;
//    @Autowired
//    private IXhMemberPayService xhMemberPayService;
//    @Autowired
//    private IXhMemberComboService xhMemberComboService;
//    @Autowired
//    private IXhMemberMoneyService xhMemberMoneyService;
//    @Autowired
//    private WeChatSendSubscribeMessageService weChatSendSubscribeMessageService;
    @Autowired
    private RedissonDistributedLock redissonDistributedLock;

    // '操作类型: 1.押金2.套餐3.余额'
    private static String payType = "payType";
    // 订单号
    private static String orderNo = "orderNo";


    /**
     * 小程序支付
     *
     * @param httpServletRequest
     * @return
     */
    @Override
    public BaseResponse wxPay(XhMember member, HttpServletRequest httpServletRequest, WxPayDTO wxPayDTO) {
        Integer id = member.getId();
        String openId = member.getOpenId();
        // 商品描述
        String description = wxPayDTO.getDescription();
        // 押金金额(元)
        BigDecimal payPrice = wxPayDTO.getPayPrice();
        // 效验订单信息
        if (StringUtils.isEmpty(wxPayDTO.getDepositOrderNo()) && StringUtils.isEmpty(wxPayDTO.getComboOrderNo())) {
            return null;
        }
        //  存自定义参数 效验订单信息   '操作类型: 1.押金 2.套餐 3.余额'
        JSONObject jsonObject = new JSONObject();
        if (!StringUtils.isEmpty(wxPayDTO.getDepositOrderNo())) {
//            XhMemberDepositOrder depositOrder = xhMemberDepositOrderService.getOne(
//                    new QueryWrapper<XhMemberDepositOrder>()
//                            .lambda()
//                            .eq(XhMemberDepositOrder::getOrderNo, wxPayDTO.getDepositOrderNo())
//                            .eq(XhMemberDepositOrder::getMemberId, id));
//            if (StringUtils.isEmpty(depositOrder)) return null;
//            if (depositOrder.getPayPrice().compareTo(wxPayDTO.getPayPrice()) != CommonConstant.ZERO) {
//                return null;
//            }
            jsonObject.put(payType, String.valueOf(CommonConstant.ONE));
            jsonObject.put(orderNo, wxPayDTO.getDepositOrderNo());
        }
        if (!StringUtils.isEmpty(wxPayDTO.getComboOrderNo())) {
            jsonObject.put(payType, String.valueOf(CommonConstant.TWO));
            jsonObject.put(orderNo, wxPayDTO.getComboOrderNo());
        }
        if (StringUtils.isEmpty(jsonObject)) return null;

        String no = (String) jsonObject.get(orderNo);
        // 换算后的金额(分)
        BigDecimal multiply = payPrice.multiply(new BigDecimal(100));
        // 支付返回
        return WeChatUtil.weChatPay(openId, description, jsonObject, no, multiply);
    }

    /**
     * @param request
     * @param response
     * @return void
     * @Description: 微信支付回调接口
     * @author lyz
     * @version [1.0, 2021-04-27]
     */
    @Override
    public void payNotify(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> map = new HashMap<>(12);
        ZLock zLock = null;
        try {
            String plainText = WeChatUtil.WeChatNotify(request);
            if (StrUtil.isNotEmpty(plainText)) {
                WxPayCallback wxPayCallback = JSONObject.parseObject(plainText, WxPayCallback.class);
                JSONObject jsonObject = JSONObject.parseObject(wxPayCallback.getAttach());
                // 效验订单信息   '操作类型: 1.押金 2.套餐 3.余额'
                //{"payType":"1","orderNo":"KH-202104271349261124292"}
                //{"payType":"2","orderNo":"TC-202104251054532245865"}
                String payType = (String) jsonObject.get("payType");
                String orderNo = (String) jsonObject.get("orderNo");
                // TODO redis 分布式锁
                zLock = redissonDistributedLock.tryLock(orderNo, 2L, 5L, TimeUnit.SECONDS);
                //操作类型: 1.押金 2.套餐 3.余额
                if (payType.equals(CommonConstant.ONE.toString())) {
                    // 修改押金订单状态. 修改流水
                    this.updateDepositOrder(orderNo, wxPayCallback);
                } else {
                    // 修改套餐状态.改流水.添加套餐信息
                    this.updateComboOrder(orderNo, wxPayCallback);
                }
                response.setStatus(200);
                map.put("code", "SUCCESS");
                map.put("message", "SUCCESS");
            } else {
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "签名错误");
            }
            response.setHeader("Content-type", ContentType.JSON.toString());
            response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
            response.flushBuffer();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                zLock.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * @return java.lang.String
     * @Description: 获取平台证书
     * @author lyz
     * @version [1.0, 2021-04-27]
     */
    @Override
    public String v3Get() {
        return WeChatUtil.getV3Cred();
    }


    /**
     * @param orderNo       订单号
     * @param wxPayCallback 回调数据
     * @return void
     * @Description: 套餐回调处理
     * @author lyz
     * @version [1.0, 2021-04-25]
     */
    @Override
    public void updateComboOrder(String orderNo, WxPayCallback wxPayCallback) {

//        XhMemberComboOrder comboOrder = xhMemberComboOrderService.getComboOrderByOrderNo(orderNo);

//        if (StringUtils.isEmpty(comboOrder)) {
//            return;
//        }
        // 订单状态：0.待支付(默认)1.已付款2.支付完成(回调确认)3.已关闭(订单超时)
//        if (CommonConstant.ZERO.equals(comboOrder.getOrderStatus())) {
//            comboOrder.setOrderStatus(CommonConstant.TWO);
//            xhMemberComboOrderService.updateById(comboOrder);
//             修改流水
//            xhMemberPayService.updateMemberOrderPay(orderNo, wxPayCallback, CommonConstant.ONE, comboOrder.getShopId());
        // 累计用户套餐
//            xhMemberComboService.addMemberCombo(comboOrder);
//            // 发送站内消息
//            XhMember member = xhMemberService.getById(comboOrder.getMemberId());
//            MessageReserve manager = new MessageReserve();
//            manager.setPhrase2("购买套餐");
//            manager.setTime3(comboOrder.getPayPrice().toString());
//            manager.setOpenId(member.getOpenId());
//            manager.setTemplateId(MessageTemplate.PAY_SUCCEED_TEMPLATE_ID);
//            weChatSendSubscribeMessageService.sendMessage(manager);
//        }
    }

    /**
     * @param orderNo       订单号
     * @param wxPayCallback 回调数据
     * @return void
     * @Description: 押金回调操作
     * @author lyz
     * @version [1.0, 2021-04-25]
     */
    @Override
    public void updateDepositOrder(String orderNo, WxPayCallback wxPayCallback) {
//        // 根据type 走不同的逻辑   '订单状态：0.待支付(默认)1.已付款2.支付完成(回调确认)3.已退款4.已关闭(订单超时)'
//        XhMemberDepositOrder depositOrder = xhMemberDepositOrderService.getOne(
//                new QueryWrapper<XhMemberDepositOrder>()
//                        .lambda()
//                        .eq(XhMemberDepositOrder::getOrderNo, orderNo)
//                        .eq(XhMemberDepositOrder::getOrderStatus, CommonConstant.ONE));
//        // 查询没有押金订单的时候 直接返回.
//        if (StringUtils.isEmpty(depositOrder)) {
//            return;
//        }
//        // 押金成功回调后修改订单表状态 ,订单状态：0.待支付(默认)1.已支付2.已完成3.已关闭
//        depositOrder.setOrderStatus(CommonConstant.TWO);
//        xhMemberDepositOrderService.updateById(depositOrder);
//        // 微信返回的数据是分,分转元
//        BigDecimal total = new BigDecimal(wxPayCallback.getAmount().getTotal());
//        total = total.divide(new BigDecimal("100"), 2, BigDecimal.ROUND_DOWN);
//        // 用户钱包表加押金金额
//        xhMemberMoneyService.addDepositOperation(depositOrder.getMemberId(), total);
//        // 流水
//        xhMemberPayService.updateMemberOrderPay(orderNo, wxPayCallback, CommonConstant.ONE, depositOrder.getShopId());
//        // 判断用户是否绑定过门店, 初次绑定 添加绑定门店id跟绑定时间
//        XhMember member = xhMemberService.getById(depositOrder.getMemberId());
//        if (!StringUtils.isEmpty(member) && StringUtils.isEmpty(member.getShopId())) {
//            member.setShopId(depositOrder.getShopId());
//            member.setShopBindingTime(DateUtil.now());
//            xhMemberService.updateById(member);
//        }
//        // 发送站内消息
//        MessageDeposit manager = new MessageDeposit();
//        manager.setCharacter_string1(orderNo);
//        manager.setAmount2(total.toString());
//        manager.setDate3(wxPayCallback.getSuccessTime());
//        manager.setPhrase4("在线支付");
//        manager.setOpenId(member.getOpenId());
//        manager.setTemplateId(MessageTemplate.DEPOSIT_TEMPLATE_ID);
//        weChatSendSubscribeMessageService.sendMessage(manager);
    }

    /**
     * @param memberId
     * @return java.lang.String
     * @Description: 退款申请
     * @author lyz
     * @version [1.0, 2021-04-27]
     */
    @Override
    public BaseResponse refund(Integer memberId) {
//        // 获取用户押金订单
//        XhMemberDepositOrder depositOrder = xhMemberDepositOrderService.getOne(new QueryWrapper<XhMemberDepositOrder>().lambda().eq(XhMemberDepositOrder::getMemberId, memberId)
//                .eq(XhMemberDepositOrder::getOrderStatus, CommonConstant.TWO));
//        if (StringUtils.isEmpty(depositOrder)) {
//            return BaseResponse.error("没有支付的押金订单");
//        }
//        String orderNo = depositOrder.getOrderNo();
//        XhMemberPay memberPay = xhMemberPayService.getOne(new QueryWrapper<XhMemberPay>().lambda().eq(XhMemberPay::getOrderNo, orderNo));
//        // 微信退款接口
//        String refund = wxRefund(memberPay);
//        WxRefundCallback wxRefundCallback = JSONObject.parseObject(refund, WxRefundCallback.class);
//        if (!StringUtils.isEmpty(wxRefundCallback.getOutRefundNo())) {
//            memberPay.setOutRefundNo(wxRefundCallback.getOutRefundNo());
//        }
//        if (!StringUtils.isEmpty(wxRefundCallback.getRefundId())) {
//            memberPay.setRefundId(wxRefundCallback.getRefundId());
//        }
//        xhMemberPayService.updateById(memberPay);
//        return BaseResponse.success(refund);
        return BaseResponse.success();
    }


    /**
     * @param request
     * @param response
     * @return void
     * @Description: 微信退款回调
     * @author lyz
     * @version [1.0, 2021-04-29]
     */
    @Override
    @Transactional
    public void refundNotify(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> map = new HashMap<>(12);
        ZLock zLock = null;
        try {
            // 回调数据封装
            String plainText = WeChatUtil.WeChatNotify(request);
            WxRefundCallback wxRefundCallback = JSONObject.parseObject(plainText, WxRefundCallback.class);
            // 回调逻辑
            if (!StringUtils.isEmpty(wxRefundCallback)) {
                // 商户退款单号
                String outRefundNo = wxRefundCallback.getOutRefundNo();
                // 微信支付退款号
                String refundId = wxRefundCallback.getRefundId();
                // 流水表修改
                XhMemberPay memberPay = updateXhMemberPay(wxRefundCallback, outRefundNo, refundId);
                if (!StringUtils.isEmpty(memberPay)) {
                    // 订单表修改
                    BigDecimal total = wxRefundCallback.getAmount().getPayerRefund();
                    total = total.divide(new BigDecimal("100"), 2, BigDecimal.ROUND_DOWN);
                    // TODO redis 分布式锁
                    zLock = redissonDistributedLock.tryLock(outRefundNo, 2L, 5L, TimeUnit.SECONDS);
                    if (!StringUtils.isEmpty(zLock.getLock())) {
                        updateMemDepositOrder(wxRefundCallback.getSuccessTime(), outRefundNo, total, memberPay);
                        zLock.close();
                    }
                    response.setStatus(200);
                    map.put("code", "SUCCESS");
                    map.put("message", "SUCCESS");
                } else {
                    response.setStatus(500);
                    map.put("code", "ERROR");
                    map.put("message", "签名错误");
                }
            } else {
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "签名错误");
            }
            response.setHeader("Content-type", ContentType.JSON.toString());
            response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
            response.flushBuffer();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                zLock.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @param successTime 成功时间
     * @param outRefundNo 退款订单号
     * @param memberId    用户id
     * @param total       退款金额
     * @return void
     * @Description: 发退款送站内信
     * @author lyz
     * @version [1.0, 2021-05-07]
     */
    private void sendMessage(String successTime, String outRefundNo, Integer memberId, BigDecimal total) {
//        XhMember member = xhMemberService.getById(memberId);
//        MessageDepositReturn depositReturn = new MessageDepositReturn();
//        depositReturn.setTime1(successTime);
//        depositReturn.setAmount2(total.toString());
//        depositReturn.setCharacter_string3(outRefundNo);
//        depositReturn.setOpenId(member.getOpenId());
//        depositReturn.setTemplateId(MessageTemplate.DEPOSIT_RETURN_SUCCEED_ID);
//        weChatSendSubscribeMessageService.sendMessage(depositReturn);
    }

    /**
     * @param total
     * @param memberPay
     * @return void
     * @Description: 扣除押金金额
     * @author lyz
     * @version [1.0, 2021-05-07]
     */
    private void updateMemDepositOrder(String successTime, String outRefundNo, BigDecimal total, XhMemberPay memberPay) {
//        String orderNo = memberPay.getOrderNo();
//        Integer memberId = memberPay.getMemberId();
//        XhMemberDepositOrder depositOrder = xhMemberDepositOrderService.getOne(new QueryWrapper<XhMemberDepositOrder>().lambda()
//                .eq(XhMemberDepositOrder::getOrderNo, orderNo).eq(XhMemberDepositOrder::getMemberId, memberId));
//        if (!StringUtils.isEmpty(depositOrder) && depositOrder.getOrderStatus().equals(CommonConstant.TWO)) {
//            depositOrder.setOrderStatus(CommonConstant.THREE);
//            xhMemberDepositOrderService.updateById(depositOrder);
//            // 扣除钱包表押金
//            xhMemberMoneyService.subDepositOperation(memberId, total);
//            sendMessage(successTime, outRefundNo, memberPay.getMemberId(), total);
//        }
    }

    private XhMemberPay updateXhMemberPay(WxRefundCallback wxRefundCallback, String outRefundNo, String refundId) {
        XhMemberPay memberPay = new XhMemberPay();
//        memberPay = xhMemberPayService.getOne(new QueryWrapper<XhMemberPay>().lambda().eq(XhMemberPay::getRefundId, refundId));
//        if (StringUtils.isEmpty(memberPay)) {
//            memberPay = xhMemberPayService.getOne(new QueryWrapper<XhMemberPay>().lambda().eq(XhMemberPay::getOutRefundNo, outRefundNo));
//        }
//        // 当查询出来的状态为2的是修改状态为4 '1.支付中,2.已完成.3支付失败.4.支付退还完成'
//        log.info("押金回调修改流水记录 订单号 = {},流水状态 = {} ", outRefundNo, memberPay.getPayTypes());
//        if (!StringUtils.isEmpty(memberPay) && CommonConstant.TWO.equals(memberPay.getPayTypes())) {
//            Date date = com.xingheng.common.utils.DateUtil.dealDateFormat(wxRefundCallback.getSuccessTime());
//            String format = DateFormatUtils.format(date, "yyyy-MM-dd HH:dd:ss");
//            memberPay.setOutRefundNo(wxRefundCallback.getOutRefundNo());
//            memberPay.setRefundId(wxRefundCallback.getRefundId());
//            memberPay.setPayerRefund(wxRefundCallback.getAmount().getPayerRefund());
//            memberPay.setUserReceivedAccount(wxRefundCallback.getUserReceivedAccount());
//            memberPay.setRefundSuccessTime(format);
//            memberPay.setRefundStatus(wxRefundCallback.getRefundStatus());
//            memberPay.setPayTypes(CommonConstant.FOUR);
//            memberPay.setPayStatus(CommonConstant.ZERO);
//            xhMemberPayService.updateById(memberPay);
//        }
        return memberPay;
    }

    /**
     * @param memberPay 商户订单号
     * @return void
     * @Description: 微信退款接口
     * @author lyz
     * @version [1.0, 2021-04-27]
     */
    private String wxRefund(XhMemberPay memberPay) {
        return WeChatUtil.getWxRefund(memberPay);
    }

    /**
     * @return void
     * @Description: 创建微信支付分订单
     * @author lyz
     * @version [1.0, 2021-05-06]
     */
    @Override
    public void payScore() {
        WeChatUtil.payScore();
    }

    /**
     * @param request
     * @param response
     * @return void
     * @Description: 创建微信支付分回调
     * @author lyz
     * @version [1.0, 2021-05-06]
     */
    @Override
    public void payScoreNotify(HttpServletRequest request, HttpServletResponse response) {

    }
}
